#ifndef DODO_NOISE_FILTER_H
#define DODO_NOISE_FILTER_H

#include <quigon.h>
#include <vector>
#include <list>

namespace quigon
{
class Noise_Filter_Proto
{
public:
	Noise_Filter_Proto(size_t low_index, size_t high_index, double low_buddy_num, double high_buddy_num, size_t low_limit_index, size_t high_limit_index)
			: top_weight(high_limit_index + 1),
			bottom_weight(high_limit_index + 1)
	{
		for (size_t i = 0; i <= high_limit_index; ++i)
		{
			top_weight[i].clear();
			bottom_weight[i].clear();
		}
//			std::cout << "li: " << low_index << ", hi: " << high_index << ", lb: " << low_buddy_num << ", hb: " << high_buddy_num << std::endl;
		for (size_t i = low_index; i <= high_index && i <= high_limit_index; ++i)
		{
			double buddy_num = interp(low_index, low_buddy_num, high_index, high_buddy_num, i);
//				std::cout <<  "i = " << i << " ,buddy_num = " << buddy_num << std::endl;
			for (size_t j = 1; j <= buddy_num; ++j)
			{
				double weight = interp(0.0, 1.0, buddy_num, 0.0, static_cast<double>(j));
				if (i + j <= high_limit_index)
					top_weight[i].push_back(weight);
				if (static_cast<int>(i) - static_cast<int>(j) >= static_cast<int>(low_limit_index))
					bottom_weight[i].push_back(weight);
			}
		}
	}

	// required Tline fields:
	// [] , size()
	// value_type == double or other type for maths.
	template<class Tline>
	bool operator()(Tline &line, double trigger_value = -999.9, size_t lowest_trigger_index = 0)
	{
		std::vector<typename Tline::value_type> old(line.begin(), line.end());
		size_t start = 0;
		if (trigger_value > 0.0)
		{
			for (start = lowest_trigger_index; start < line.size(); ++start)
			{
				if (old[start] <= trigger_value)
				{
					break;
				}
			}
		}
		for (size_t i = start; i < line.size(); ++i)
		{
			typename Tline::value_type sum = old[i];
			double total_weight = 1.0;

			typename std::list<double>::const_iterator iter;
			iter = top_weight[i].begin();
			for (size_t j = 1 ; j <= top_weight[i].size(); ++j, ++iter)
			{
				sum += old[i + j] * (*iter);
				total_weight += (*iter);
			}
			iter = bottom_weight[i].begin();
			for (size_t j = 1; j <= bottom_weight[i].size(); ++j, ++iter)
			{
				sum += old[i - j] * (*iter);
				total_weight += (*iter);
			}
//				std::cout << "index: " << i << ", total_weight: " << total_weight << std::endl;
			line[i] = sum / total_weight;

		}
		return true;
	}
protected:

	std::vector< std::list<double> > top_weight;
	std::vector< std::list<double> > bottom_weight;
};
}

#endif

